JavaScript30
第二十三天要做的專案是學習語音撥放的 API,做出可以閱讀文字輸入的語音撥放器,並且可以調整語速及語調
Github 檔案位置:23 - Speech Synthesis
網站初始的樣子
可以先玩玩 最後的成品
首先一開始還是選取所有要操控的元素
今天要用到的 API 就是 SpeechSynthesisUtterance,他可以利用電腦內建的語音服務去閱讀文字內容
const msg = new SpeechSynthesisUtterance();
let voices = [];
const voicesDropdown = document.querySelector('[name="voice"]');
const options = document.querySelectorAll('[type="range"], [name="text"]');
const speakButton = document.querySelector('#speak');
const stopButton = document.querySelector('#stop');
msg.text = document.querySelector('[name="text"]').value;
這個 API 要求我們在撥放前選取好要使用的語音服務 voice,因此這裡利用 speechSynthesis.getVoices() 獲取所有可用的語音服務,
再透過 filter 把服務限縮到英文和中文語音,並利用 map 把陣列的資料整理為可視化的 HTML 元素,最後以 join 將其合併並消除逗號
function populateVoices() {
voices = speechSynthesis.getVoices()
// console.log(voices);
voicesDropdown.innerHTML = voices
.filter(voice => voice.lang.includes('en') || voice.lang.includes('zh-TW'))
.map(voice => `<option value="${voice.name}">${voice.name} (${voice.lang})</option>`)
.join('');
}
speechSynthesis.addEventListener('voiceschanged', populateVoices);
就得到只有中英文的語音服務選單了
備註:voiceschanged 事件在加載進網頁時會自動觸發一次,在此專案中僅利用他建立出語系清單,後續會再監聽語系的切換
接下來就是要實現語音撥放以及語速、語調等係數的調整了
以下來讓我們介紹一下各參數的設定
在這裡我們先實作撥放的功能,再切換語速及語調
這裡的 voices 是我們剛才提取出的所有語系,在語系清單的 change 事件觸發時,就會將目前選取的語系賦值給 msg.voice
接著跟 Day1 將撥放時間歸零的方式很像,在撥放前先將正在撥放的音訊清除,否則要等到前一段撥放完下一段才會再次撥放
startOver = true
是 ES6 的新語法,可以在沒有變數傳入時默認 startOver
值為 true,這樣只要在需要停止音樂時傳入 false 即可做到開關
function setVoice() {
msg.voice = voices.find(voice => voice.name === this.value);
toggle();
}
function toggle(startOver = true) {
speechSynthesis.cancel();
if (startOver) {
speechSynthesis.speak(msg);
}
}
voicesDropdown.addEventListener('change', setVoice);
speakButton.addEventListener('click', toggle);
stopButton.addEventListener('click', () => toggle(false));
最後這裡是調整語速、語調、朗讀內容的部分,只要使用者改變了這些值就會觸發 setOption()
,這裡的 this.name
是 HTML 中原先就設定好的值
const options = document.querySelectorAll('[type="range"], [name="text"]');
function setOption() {
console.log(this.name, this.value);
msg[this.name] = this.value;
toggle();
}
options.forEach(option => option.addEventListener('change', setOption));
const msg = new SpeechSynthesisUtterance();
let voices = [];
const voicesDropdown = document.querySelector('[name="voice"]');
const options = document.querySelectorAll('[type="range"], [name="text"]');
const speakButton = document.querySelector('#speak');
const stopButton = document.querySelector('#stop');
msg.text = document.querySelector('[name="text"]').value;
function populateVoices() {
console.log('owo');
voices = this.getVoices();
// console.log(voices);
voicesDropdown.innerHTML = voices
.filter(voice => voice.lang.includes('en') || voice.lang.includes('zh-TW'))
.map(voice => `<option value="${voice.name}">${voice.name} (${voice.lang})</option>`)
.join('');
}
function setVoice() {
msg.voice = voices.find(voice => voice.name === this.value);
toggle();
}
function toggle(startOver = true) {
speechSynthesis.cancel();
if (startOver) {
speechSynthesis.speak(msg);
}
}
function setOption() {
console.log(this.name, this.value);
msg[this.name] = this.value;
toggle();
}
speechSynthesis.addEventListener('voiceschanged', populateVoices);
voicesDropdown.addEventListener('change', setVoice);
options.forEach(option => option.addEventListener('change', setOption));
speakButton.addEventListener('click', toggle);
stopButton.addEventListener('click', () => toggle(false));
以上是第二十三天的製作紀錄,如有錯誤或不足的地方還請多多指教 >.<
JavaScript Text-To-Speech - #JavaScript30 23/30
[ Alex 宅幹嘛 ] 深入淺出 Javascript30 快速導覽 | Day 23 - Speech Synthesis
MDN Web Docs